﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;

namespace TinyERP.Framework
{
    public class ApplicationNode
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string UIClassName { get; set; }
        public string IconKey { get; set; }
        public IList<ApplicationNode> Children { get; set; }
        public ApplicationNode()
        {
            Children = new List<ApplicationNode>();
        }
    }
    public class Module
    {
        public string Name { get; set; }
        public string Assembly { get; set; }
    }
    public interface ITinyERPConfigProvider
    {
        void LoadConfiguration(ApplicationConfiguration configuration);
        void SaveConfiguration(ApplicationConfiguration configuration);
    }

    public class ApplicationConfiguration
    {
        private static ApplicationConfiguration instance;
        private ApplicationConfiguration()
        {
            ApplicationStructure = new List<ApplicationNode>();
            Modules = new List<Module>();
        }
        public static ApplicationConfiguration GetInstance()
        {
            if (instance == null)
            {
                instance = new ApplicationConfiguration();
            }
            return instance;
        }

        public IList<ApplicationNode> ApplicationStructure { get; set; }
        public IList<Module> Modules { get; set; }
        public string PluginPath { get; set; }
        public string ApplicationName { get; set; }
        public string NavigationView { get; set; }
        public string DefaultLanguage { get; set; }
        public string DefaultTheme { get; set; }
        public string NewShortcut { get; set; }
        public string DeleteShortcut { get; set; }
        public string EditShortcut { get; set; }
        public string CloseShortcut { get; set; }
        public string FindShortcut { get; set; }
        public string ApplicationMode { get; set; }
    }

    public class XmlConfigurationProvider : ITinyERPConfigProvider
    {
        private ApplicationConfiguration configuration;
        private string filePath;
        private Assembly assembly;
        private string resourcePath;
        public XmlConfigurationProvider(string filePath)
        {
            this.configuration = configuration;
            this.filePath = filePath;
        }
        public XmlConfigurationProvider(Assembly assembly, string resourcePath)
        {
            this.assembly = assembly;
            this.resourcePath = resourcePath;
        }

        private void LoadConfigFromExternalFile(string filePath)
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(filePath);
            LoadConfigurationFromXmlDocument(xmlDocument);
        }

        private void LoadConfigFromResourceFile(Assembly assembly, string resourcePath)
        {
            Stream stream = assembly.GetManifestResourceStream(resourcePath);
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(stream);
            LoadConfigurationFromXmlDocument(xmlDocument);
        }
        private void LoadConfigurationFromXmlDocument(XmlDocument xmlDocument)
        {
            LoadApplicationSetting(xmlDocument);
            LoadModuleList(xmlDocument);
            LoadApplicationStructure(xmlDocument);
            LoadUISetting(xmlDocument);
            LoadShortcutSetting(xmlDocument);
        }
        private void LoadModuleList(XmlDocument xmlDocument)
        {
            XmlNodeList xmlModuleNodeList = xmlDocument.SelectNodes("application-config/plugin-modules/module");
            foreach (XmlNode xmlModuleNode in xmlModuleNodeList)
            {
                Module module = new Module();
                module.Name = GetAttributeValue(xmlModuleNode, "name");
                module.Assembly = GetAttributeValue(xmlModuleNode, "assembly");
                configuration.Modules.Add(module);
            }
        }
        private void LoadApplicationSetting(XmlDocument xmlDocument)
        {
            configuration.ApplicationName = xmlDocument.SelectSingleNode("application-config/app-name").InnerText;
            configuration.PluginPath = xmlDocument.SelectSingleNode("application-config/plugin-path").InnerText;
            configuration.ApplicationMode = xmlDocument.SelectSingleNode("application-config/app-mode").InnerText;
        }

        private void LoadShortcutSetting(XmlDocument xmlDocument)
        {
            configuration.CloseShortcut = xmlDocument.SelectSingleNode("application-config/shortcuts/close-shortcut").InnerText;
            configuration.EditShortcut = xmlDocument.SelectSingleNode("application-config/shortcuts/edit-shortcut").InnerText;
            configuration.FindShortcut = xmlDocument.SelectSingleNode("application-config/shortcuts/find-shortcut").InnerText;
            configuration.NewShortcut = xmlDocument.SelectSingleNode("application-config/shortcuts/new-shortcut").InnerText;
            configuration.DeleteShortcut = xmlDocument.SelectSingleNode("application-config/shortcuts/delete-shortcut").InnerText;
        }

        private void LoadUISetting(XmlDocument xmlDocument)
        {
            configuration.NavigationView = xmlDocument.SelectSingleNode("application-config/ui-settings/navigation-view").InnerText;
            configuration.DefaultLanguage = xmlDocument.SelectSingleNode("application-config/ui-settings/default-language").InnerText;
            configuration.DefaultTheme = xmlDocument.SelectSingleNode("application-config/ui-settings/default-theme").InnerText;
        }
        private void LoadApplicationStructure(XmlDocument xmlDocument)
        {
            configuration.ApplicationStructure.Clear();
            XmlNodeList xmlRootNodeList = xmlDocument.SelectNodes("application-config/app-structure/node");
            if (xmlRootNodeList == null)
            {
                return;
            }
            foreach (XmlNode xmlRootNode in xmlRootNodeList)
            {
                ApplicationNode node = ReadNodeInfoFromXml(xmlRootNode);
                if (node != null)
                {
                    configuration.ApplicationStructure.Add(node);
                }
            }
        }

        private ApplicationNode ReadNodeInfoFromXml(XmlNode formNodeXml)
        {
            ApplicationNode formNode = new ApplicationNode();
            formNode.ID = formNodeXml.Attributes["id"].Value;
            formNode.Title = formNodeXml.Attributes["title"].Value;
            formNode.IconKey = GetAttributeValue(formNodeXml, "icon");
            if (formNodeXml.Attributes["uiclass"] != null)
            {
                formNode.UIClassName = formNodeXml.Attributes["uiclass"].Value;
            }


            XmlNode descriptionNodeXml = formNodeXml.SelectSingleNode("description");
            if (descriptionNodeXml != null)
            {
                formNode.Description = descriptionNodeXml.InnerText;
            }
            XmlNode childrenNodeXml = formNodeXml.SelectSingleNode("children");
            if (childrenNodeXml != null && childrenNodeXml.ChildNodes != null && childrenNodeXml.ChildNodes.Count > 0)
            {
                foreach (XmlNode childFormNodeXml in childrenNodeXml.ChildNodes)
                {
                    ApplicationNode childNode = ReadNodeInfoFromXml(childFormNodeXml);
                    if (childNode != null)
                    {
                        formNode.Children.Add(childNode);
                    }
                }
            }
            return formNode;
        }


        private string GetAttributeValue(XmlNode xmlNode, string attributeName)
        {
            if (xmlNode == null || attributeName == null)
            {
                return null;
            }
            if (xmlNode.Attributes[attributeName] == null)
            {
                return null;
            }
            return xmlNode.Attributes[attributeName].Value;
        }

        public void LoadConfiguration(ApplicationConfiguration configuration)
        {
            this.configuration = configuration;
            if (assembly != null)
            {
                this.LoadConfigFromResourceFile(assembly, resourcePath);
            }
            else
            {
                this.LoadConfigFromExternalFile(filePath);
            }
        }

        public void SaveConfiguration(ApplicationConfiguration configuration)
        {

        }
    }

}
